package org.example.study11.condition;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 有界缓冲区 - 使用Condition实现生产者消费者模式
 */
public class BoundedBuffer<T> {
    private final Queue<T> buffer;          // 缓冲区队列
    private final int capacity;             // 缓冲区容量
    private final ReentrantLock lock;       // 可重入锁
    private final Condition notFull;        // "非满"条件
    private final Condition notEmpty;       // "非空"条件

    public BoundedBuffer(int capacity) {
        this.capacity = capacity;           // 设置缓冲区容量
        this.buffer = new LinkedList<>();   // 初始化缓冲区队列
        this.lock = new ReentrantLock();    // 创建可重入锁
        this.notFull = lock.newCondition(); // 创建"非满"条件变量
        this.notEmpty = lock.newCondition();// 创建"非空"条件变量
    }

    /**
     * 生产方法 - 将元素放入缓冲区
     */
    public void put(T item) throws InterruptedException {
        lock.lock();                        // 获取锁
        try {
            while (buffer.size() == capacity) { // 检查缓冲区是否已满
                System.out.println(Thread.currentThread().getName() + ": 缓冲区已满，生产者等待");
                notFull.await();            // 缓冲区已满，在notFull条件上等待
            }
            buffer.offer(item);             // 将元素放入缓冲区
            System.out.println(Thread.currentThread().getName() + ": 生产了 " + item +
                    ", 当前缓冲区大小: " + buffer.size());
            notEmpty.signal();              // 唤醒一个在notEmpty条件上等待的消费者
        } finally {
            lock.unlock();                  // 确保锁被释放
        }
    }

    /**
     * 消费方法 - 从缓冲区取出元素
     */
    public T take() throws InterruptedException {
        lock.lock();                        // 获取锁
        try {
            while (buffer.isEmpty()) {      // 检查缓冲区是否为空
                System.out.println(Thread.currentThread().getName() + ": 缓冲区为空，消费者等待");
                notEmpty.await();           // 缓冲区为空，在notEmpty条件上等待
            }
            T item = buffer.poll();         // 从缓冲区取出元素
            System.out.println(Thread.currentThread().getName() + ": 消费了 " + item +
                    ", 当前缓冲区大小: " + buffer.size());
            notFull.signal();               // 唤醒一个在notFull条件上等待的生产者
            return item;                    // 返回取出的元素
        } finally {
            lock.unlock();                  // 确保锁被释放
        }
    }

    /**
     * 获取当前缓冲区大小
     */
    public int size() {
        lock.lock();                        // 获取锁
        try {
            return buffer.size();           // 返回缓冲区当前大小
        } finally {
            lock.unlock();                  // 确保锁被释放
        }
    }
}
